package com.example.game_community.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.game_community.entity.User;
import com.example.game_community.mapper.UserMapper;
import com.example.game_community.service.UserService;
import com.example.game_community.utils.Result;
import lombok.Getter;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final ConcurrentHashMap<String, VerificationCode> codeStorage = new ConcurrentHashMap<>();
    // 验证码有效时间60秒
    private static final long CODE_TIME = 1000 * 60;
    // 验证码长度
    private static final int CODE_LENGTH = 6;

    // 用于用户进行账号和密码登录
    @Override
    public User login(User user) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, user.getUsername())
                .eq(User::getPassword, user.getPassword());
        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    public Result<User> register(User user) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, user.getUsername());
        User p = this.baseMapper.selectOne(queryWrapper);
        if (p != null) {
            return Result.error("用户名已存在");
        } else {
            // 设置当前时间为创建时间
            user.setCreateTime(LocalDateTime.now());
            this.baseMapper.insert(user);
            return Result.success("注册成功");
        }
    }

    // 发送验证码，让用户用手机号登录，获取验证码
    @Override
    public Result<User> sendVerCode(String phone) {
        if (!validPhoneNumber(phone)) {
            return Result.error("手机格式不正确");
        }

        // 生成随机验证码
        String phoneCode = generateRandomCode();

        codeStorage.put(phone, new VerificationCode(phoneCode, System.currentTimeMillis()));

        return Result.success("手机号：" + phone + "验证码：" + phoneCode);
    }

    // 让用户进行手机号码登录，验证验证码
    @Override
    public Result<?> verifyCode(String phone, String inputCode) {
        VerificationCode storedCode = codeStorage.get(phone);
        if (storedCode == null) {
            return Result.error("请先获取验证码");
        }

        if (System.currentTimeMillis() - storedCode.expireTime > CODE_TIME) {
            codeStorage.remove(phone);
            return Result.error("验证码已经过期,请重新获取");
        }

        if (!storedCode.phoneCode.equals(inputCode)) {
            return Result.error("验证码不正确");
        }

        codeStorage.remove(phone);

        // 如果验证码正确，查询用户是否存在，如果不存在则创建新用户
        if (this.baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone)) == null) {
            User user = new User();
            user.setPhone(phone);
            user.setCreateTime(LocalDateTime.now());
            this.baseMapper.insert(user);
        }

        User p = this.baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        return Result.success(p);
    }

    @Override
    public User convertTo(User user) {
        return User.builder().id(user.getId())
                .username(user.getUsername())
                .avatar(user.getAvatar())
                .build();
    }

    private String generateRandomCode() {
        Random random = new Random();
        return String.format("%0" + UserServiceImpl.CODE_LENGTH + "d",
                random.nextInt((int) Math.pow(10, UserServiceImpl.CODE_LENGTH)));
    }

    private boolean validPhoneNumber(String phone) {
        return phone.matches("^1[3-9]\\d{9}");
    }

    @Getter
    private static class VerificationCode {
        private final String phoneCode;

        private final long expireTime;

        public VerificationCode(String phoneCode, long expireTime) {
            this.phoneCode = phoneCode;
            this.expireTime = expireTime;
        }
    }

}
